﻿// <copyright file="Version.cs" company="BerlinSoft">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author>Wernfried Schwenkner</author>
// <email>wernfried@schwenkner.de</email>
// <date>2009-10-21</date>
// <summary>
// Contains the Version class.
// </summary>

using System;
using System.Data.SqlServerCe;

namespace SenseTimeTracker.Misc
{
	/// <summary>
	/// Class contains the version handling
	/// </summary>
	public class Version : ICloneable, IComparable, IComparable<Version>, IEquatable<Version>
	{
		/// <summary>
		/// Field contains the version
		/// </summary>
		private System.Version version;

		/// <summary>
		/// Initializes a new instance of the <see cref="Version"/> class.
		/// </summary>
		/// <param name="version">
		/// A string containing the major, minor, build, and revision numbers,
		/// where each number is delimited with a period character ('.').
		/// </param>
		/// <exception cref="System.ArgumentException">
		/// version has fewer than two components or more than four components.
		/// </exception>
		/// <exception cref="System.ArgumentNullException">
		/// version is null.
		/// </exception>
		/// <exception cref="System.ArgumentOutOfRangeException">
		/// A major, minor, build, or revision component is less than zero.
		/// </exception>
		/// <exception cref="System.FormatException">
		/// At least one component of version does not parse to an integer.
		/// </exception>
		/// <exception cref="System.OverflowException">
		/// At least one component of version represents a number greater than System.Int32.MaxValue.
		/// </exception>
		public Version(string version)
		{
			this.version = new System.Version(version);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Version"/> class using the specified major and minor values.
		/// </summary>
		/// <param name="major">The major version number.</param>
		/// <param name="minor">The minor version number.</param>
		/// <exception cref="System.ArgumentOutOfRangeException">
		/// major or minor is less than zero.
		/// </exception>
		public Version(int major, int minor)
		{
			version = new System.Version(major, minor);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Version"/> class using the specified major, minor, and build values.
		/// </summary>
		/// <param name="major">The major version number.</param>
		/// <param name="minor">The minor version number.</param>
		/// <param name="build">The build number.</param>
		/// <exception cref="System.ArgumentOutOfRangeException">
		/// major, minor, or build is less than zero.
		/// </exception>
		public Version(int major, int minor, int build)
		{
			version = new System.Version(major, minor, build);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Version"/> class with the specified major, minor, build, and revision numbers.
		/// </summary>
		/// <param name="major">The major version number.</param>
		/// <param name="minor">The minor version number.</param>
		/// <param name="build">The build number.</param>
		/// <param name="revision">The revision number.</param>
		/// <exception cref="System.ArgumentOutOfRangeException">
		/// major, minor, build, or revision is less than zero.
		/// </exception>
		public Version(int major, int minor, int build, int revision)
		{
			version = new System.Version(major, minor, build, revision);
		}

		/// <summary>
		/// Gets the value of the build component of the version number for the current <see cref="Version"/> object.
		/// </summary>
		/// <returns>The build number, or -1 if the build number is undefined.</returns>
		public int Build
		{
			get { return version.Build; }
		}

		/// <summary>
		/// Gets the value of the major component of the version number for the current <see cref="Version"/> object.
		/// </summary>
		/// <returns>The major version number.</returns>
		public int Major
		{
			get { return version.Major; }
		}

		/// <summary>
		/// Gets the value of the minor component of the version number for the current <see cref="Version"/> object.
		/// </summary>
		/// <returns>The minor version number.</returns>
		public int Minor
		{
			get { return version.Minor; }
		}

		/// <summary>
		/// Gets the value of the revision component of the version number for the current <see cref="Version"/> object.
		/// </summary>
		/// <returns>The revision number, or -1 if the revision number is undefined.</returns>
		public int Revision
		{
			get { return version.Revision; }
		}

		/// <summary>
		/// Initializes a new instance ov the <see cref="Version"/> class with the version read from database.
		/// </summary>
		/// <returns>The version read from database</returns>
		public static Version FromDb()
		{
			Version version = null;
			SqlCeDataReader reader = new SqlCeCommand("SELECT * from Version", DatabaseManager.DbConnection).ExecuteReader();
			if (reader.Read())
			{
				version = new Version(
					(int)reader["major"],
					(int)reader["minor"],
					(int)reader["build"]);
			}

			return version;
		}

		/// <summary>
		/// Determines whether two specified <see cref="Version"/> objects are not equal.
		/// </summary>
		/// <param name="v1">The first <see cref="Version"/> object.</param>
		/// <param name="v2">The second <see cref="Version"/> object.</param>
		/// <returns>true if v1 does not equal v2; otherwise, false.</returns>
		public static bool operator !=(Version v1, Version v2)
		{
			return v1.version != v2.version;
		}

		/// <summary>
		/// Determines whether the first specified System.Version object is less than the second specified <see cref="Version"/> object.
		/// </summary>
		/// <param name="v1">The first <see cref="Version"/> object.</param>
		/// <param name="v2">The second <see cref="Version"/> object.</param>
		/// <returns>true if v1 is less than v2; otherwise, false.</returns>
		/// <exception cref="System.ArgumentNullException">v1 is null.</exception>
		public static bool operator <(Version v1, Version v2)
		{
			return v1.version < v2.version;
		}

		/// <summary>
		/// Determines whether the first specified System.Version object is less than or equal to the second <see cref="Version"/> object.
		/// </summary>
		/// <param name="v1">The first <see cref="Version"/> object.</param>
		/// <param name="v2">The second <see cref="Version"/> object.</param>
		/// <returns>true if v1 is less than or equal to v2; otherwise, false.</returns>
		/// <exception cref="System.ArgumentNullException">v1 is null.</exception>
		public static bool operator <=(Version v1, Version v2)
		{
			return v1.version <= v2.version;
		}

		/// <summary>
		/// Determines whether two specified <see cref="Version"/> objects are equal.
		/// </summary>
		/// <param name="v1">The first <see cref="Version"/> object.</param>
		/// <param name="v2">The second <see cref="Version"/> object.</param>
		/// <returns>true if v1 equals v2; otherwise, false.</returns>
		public static bool operator ==(Version v1, Version v2)
		{
			return v1.version == v2.version;
		}

		/// <summary>
		/// Determines whether the first specified System.Version object is greater than the second specified <see cref="Version"/> object.
		/// </summary>
		/// <param name="v1">The first <see cref="Version"/> object.</param>
		/// <param name="v2">The second <see cref="Version"/> object.</param>
		/// <returns>true if v1 is greater than v2; otherwise, false.</returns>
		public static bool operator >(Version v1, Version v2)
		{
			return v1.version > v2.version;
		}

		/// <summary>
		/// Determines whether the first specified System.Version object is greater than or equal to the second specified <see cref="Version"/> object.
		/// </summary>
		/// <param name="v1">The first <see cref="Version"/> object.</param>
		/// <param name="v2">The second <see cref="Version"/> object.</param>
		/// <returns>true if v1 is greater than or equal to v2; otherwise, false.</returns>
		public static bool operator >=(Version v1, Version v2)
		{
			return v1.version >= v2.version;
		}

		/// <summary>
		/// Writes tre version info back to database
		/// </summary>
		public void UpdateVersion()
		{
			SqlCeCommand command = new SqlCeCommand("UPDATE Version SET major=@major, minor=@minor, build=@build", DatabaseManager.DbConnection);
			command.Parameters.Add("@major", version.Major);
			command.Parameters.Add("@minor", version.Minor);
			command.Parameters.Add("@build", version.Build);
			command.ExecuteNonQuery();
		}

		/// <summary>
		/// Replaces the current version with the given and writes the version info back to database.
		/// </summary>
		/// <param name="version">The <see cref="Version"/> to be replaced.</param>
		public void UpdateVersion(Version version)
		{
			this.version = (System.Version)version.version.Clone();
			UpdateVersion();
		}

		/// <summary>
		/// Returns a value indicating whether the current <see cref="Version"/> object is equal to a specified object.
		/// </summary>
		/// <param name="obj">An object to compare with the current <see cref="Version"/> object, or null.</param>
		/// <returns>
		/// true if the current System.Version object and obj are both <see cref="Version"/>
		/// objects, and every component of the current <see cref="Version"/> object matches
		/// the corresponding component of obj; otherwise, false.
		/// </returns>
		public override bool Equals(object obj)
		{
			return version.Equals(obj);
		}

		/// <summary>
		/// Returns a hash code for the current <see cref="Version"/> object.
		/// </summary>
		/// <returns>A 32-bit signed integer hash code.</returns>
		public override int GetHashCode()
		{
			return version.GetHashCode();
		}

		/// <summary>
		/// Converts the value of the current <see cref="Version"/> object to its equivalent
		/// System.String representation.
		/// </summary>
		/// <returns>
		/// The System.String representation of the values of the major, minor, build,
		/// and revision components of the current <see cref="Version"/> object, as depicted
		/// in the following format. Each component is separated by a period character
		/// ('.'). Square brackets ('[' and ']') indicate a component that will not appear
		/// in the return value if the component is not defined: major.minor[.build[.revision]]
		/// For example, if you create a <see cref="Version"/> object using the constructor
		/// Version(1,1), the returned string is "1.1". If you create a <see cref="Version"/>
		/// object using the constructor Version(1,3,4,2), the returned string is "1.3.4.2".
		/// </returns>
		public override string ToString()
		{
			return version.ToString();
		}

		/// <summary>
		/// Converts the value of the current <see cref="Version"/> object to its equivalent
		/// System.String representation. A specified count indicates the number of components
		/// to return.
		/// </summary>
		/// <param name="fieldCount">The number of components to return. The fieldCount ranges from 0 to 4.</param>
		/// <returns>
		/// The System.String representation of the values of the major, minor, build,
		/// and revision components of the current <see cref="Version"/> object, each separated
		/// by a period character ('.'). The fieldCount parameter determines how many
		/// components are returned.fieldCount Return Value 0 An empty string ("").
		/// 1 major 2 major.minor 3 major.minor.build 4 major.minor.build.revision For
		/// example, if you create <see cref="Version"/> object using the constructor Version(1,3,5),
		/// ToString(2) returns "1.3" and ToString(4) throws an exception.
		/// </returns>
		/// <exception cref="System.ArgumentException">
		/// fieldCount is less than 0, or more than 4.-or- fieldCount is more than the
		/// number of components defined in the current System.Version object.
		/// </exception>
		public string ToString(int fieldCount)
		{
			return version.ToString(fieldCount);
		}

		#region ICloneable Members
		/// <summary>
		/// Returns a new <see cref="Version"/> object whose value is the same as the current <see cref="Version"/> object.
		/// </summary>
		/// <returns>A new System.Object whose values are a copy of the current <see cref="Version"/> object.</returns>
		public object Clone()
		{
			return new Version(version.Major, version.Minor, version.Build, version.Revision);
		}
		#endregion

		#region IComparable Members
		/// <summary>
		/// Compares the current <see cref="Version"/> object to a specified object and returns an indication of their relative values.
		/// </summary>
		/// <param name="version">An object to compare, or null.</param>
		/// <returns>
		/// Return Value Description Less than zero The current <see cref="Version"/> object
		/// is a version before version. Zero The current <see cref="Version"/> object is the
		/// same version as version. Greater than zero The current <see cref="Version"/> object
		/// is a version subsequent to version.-or- version is null.
		/// </returns>
		/// <exception cref="System.ArgumentException">version is not of type <see cref="Version"/>.</exception>
		public int CompareTo(object version)
		{
			if (version.GetType() != typeof(Version))
			{
				throw new ArgumentException("version is not type of Version");
			}

			return this.version.CompareTo(version);
		}
		#endregion

		#region IComparable<Version> Members
		/// <summary>
		/// Compares two instances of versions
		/// </summary>
		/// <param name="value">the version zo be compared with</param>
		/// <returns>
		/// Return Value Description Less than zero The current <see cref="Version"/> object
		/// is a version before value. Zero The current <see cref="Version"/> object is the
		/// same version as value. Greater than zero The current <see cref="Version"/> object
		/// is a version subsequent to value. -or-value is null.
		/// </returns>
		public int CompareTo(Version value)
		{
			return version.CompareTo(value);
		}
		#endregion

		#region IEquatable<Version> Members
		/// <summary>
		/// Returns a value indicating whether the current <see cref="Version"/> object and
		/// a specified System.Version object represent the same value.
		/// </summary>
		/// <param name="other">
		/// A <see cref="Version"/> object to compare to the current <see cref="Version"/> object, or null.
		/// </param>
		/// <returns>
		/// true if every component of the current <see cref="Version"/> object matches the
		/// corresponding component of the obj parameter; otherwise, false.
		/// </returns>
		public bool Equals(Version other)
		{
			return version.Equals(other.version);
		}
		#endregion
	}
}
